/**
 * a simple options parser.
 * modify from git project.
 */
#ifndef _HAVE_PARSE_OPTIONS_H
#define _HAVE_PARSE_OPTIONS_H

 /* SYS_HAVE_STDINT_H */
#if defined(__GNUC__)
    #define SYS_HAVE_STDINT_H
#elif defined(_MSC_VER)
    #if _MSC_VER >=1600 
        #define SYS_HAVE_STDINT_H
    #endif
#endif

#ifdef SYS_HAVE_STDINT_H
	#include <stdint.h>
#else
	typedef long int intptr_t;
#endif /* !SYS_HAVE_STDINT_H */

#include <stdlib.h>
#include <string.h>

/* option types */
enum opt_t {
    /* special type */
    opt_t_end,

    /* normal */
    opt_t_int,
    opt_t_string,
    opt_t_bool
};

/* option flags */
enum opt_f {
    opt_f_noarg     = 0x1,
    opt_f_optarg    = 0x2,
    opt_f_noneg     = 0x4
};

enum parse_f {
	parse_f_none				= 0x0,
    parse_f_no_internal_help    = 0x1,
    parse_f_stop_at_non_option  = 0x2,
    parse_f_keep_unknow         = 0x4,
	parse_f_need_option  		= 0x8
};
/**
 * @param type
 *   the type of the option, you must have an opt_t_end last in your array.
 * @param name
 *   the option name, without the leading dashes, NULL if none.
 * @param help
 *   the short help associated to what the option does.
 * @param flags
 *   mask of parse_opt_option_flags.
 *   opt_f_optarg: says that the argument is optional (not for BOOLEANs)
 *   opt_f_noarg : says that this option does not take an argument
 *   opt_f_noneg : says that this option cannot be negated *
 * @param value
 *   stores pointers to the values bo be filled.
 * @param defval
 *   default value to fill (*->value) with for opt_f_optarg.
 */
struct option {
    enum opt_t  type;
    const char  *long_name;
    int         short_name;
    int         flags;
    const char  *help;
    void        *value;
    intptr_t    defval;
};

/** parse_options() will filter out the processed options and leave the
 * non-option arguments in argv[].
 * Returns the number of arguments left in argv[].
 * On error, -1 is returnd.
 */
extern int parse_options(int argc, char **argv, const struct option *options,
                         const char * const usagestr[], enum parse_f flags);

/* incremental advanced APIs */
enum {
    parse_opt_help = -1,
    parse_opt_done,
    parse_opt_non_option,
    parse_opt_unknow
};

/**
 * It's okay for the caller to consume argv/argc in the usual way.
 * Other fields of that structure are private to parse-options & should not
 * be modified in any way.
 */
struct parse_opt_ctx_t {
    const char **argv;
    const char **out;
    int argc, cpidx;
    const char *opt;
    int flags;
};

extern void parse_options_prepare(struct parse_opt_ctx_t *ctx,
                                  int argc, const char **argv,
                                  const struct option *options,
                                  enum parse_f flags);

extern int parse_options_step(struct parse_opt_ctx_t *ctx,
                              const struct option *options,
                              const char * const usagestr[]);

extern int parse_options_finalize(struct parse_opt_ctx_t *ctx);

#endif /* !_HAVE_PARSE_OPTIONS_H */
